/*
 *   Licensed to the Apache Software Foundation (ASF) under one
 *   or more contributor license agreements.  See the NOTICE file
 *   distributed with this work for additional information
 *   regarding copyright ownership.  The ASF licenses this file
 *   to you under the Apache License, Version 2.0 (the
 *   "License"); you may not use this file except in compliance
 *   with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing,
 *   software distributed under the License is distributed on an
 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *   KIND, either express or implied.  See the License for the
 *   specific language governing permissions and limitations
 *   under the License.
 *
 */

package org.apache.directory.http.client.data.model;


import java.util.ArrayList;
import java.util.List;

import org.apache.directory.shared.ldap.entry.BinaryValue;
import org.apache.directory.shared.ldap.entry.DefaultEntryAttribute;
import org.apache.directory.shared.ldap.entry.DefaultModification;
import org.apache.directory.shared.ldap.entry.EntryAttribute;
import org.apache.directory.shared.ldap.entry.Modification;
import org.apache.directory.shared.ldap.entry.ModificationOperation;
import org.apache.directory.shared.ldap.entry.StringValue;
import org.apache.directory.shared.ldap.entry.Value;
import org.apache.directory.shared.ldap.exception.LdapInvalidAttributeValueException;
import org.apache.directory.shared.ldap.schema.AttributeType;
import org.apache.directory.shared.ldap.schema.SyntaxChecker;


/**
 * TODO AttributeData.
 *
 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
 */
public class AttributeData
{
    private final EntryData parent;

    private EntryAttribute original;

    private EntryAttribute cloned;

    private AttributeType type;

    private List<Modification> mods = new ArrayList<Modification>();

    private SyntaxChecker checker;


    public AttributeData( EntryData parent, EntryAttribute attr )
    {
        this.parent = parent;
        this.original = attr;
        cloned = original.clone();
        type = cloned.getAttributeType();
        checker = type.getSyntax().getSyntaxChecker();
    }


    public boolean isDirty()
    {
        return mods.isEmpty();
    }


    public boolean isHr()
    {
        return type.getSyntax().isHumanReadable();
    }


    public boolean getBoolean()
    {
        return Boolean.parseBoolean( getString() );
    }


    public String getString()
    {
        try
        {
            return cloned.getString();
        }
        catch ( LdapInvalidAttributeValueException e )
        {
            e.printStackTrace();
            // to avoid try-catch hell on the caller
            throw new IllegalStateException( e );
        }
    }


    public byte[] getBytes()
    {
        try
        {
            return cloned.getBytes();
        }
        catch ( LdapInvalidAttributeValueException e )
        {
            e.printStackTrace();
            // to avoid try-catch hell on the caller
            throw new IllegalStateException( e );
        }
    }


    public boolean isModifiable()
    {
        if ( type.isReadOnly() || ( !type.isUserModifiable() ) )
        {
            return false;
        }

        return true;
    }


    private boolean add( Value<?> value )
    {

        boolean valid = checker.isValidSyntax( value.get() );
        if ( !valid )
        {
            return false;
        }

        ModificationOperation op = ModificationOperation.ADD_ATTRIBUTE;

        if ( type.isSingleValued() )
        {
            mods.clear();
            op = ModificationOperation.REPLACE_ATTRIBUTE;
        }

        Modification mod = new DefaultModification();
        mod.setOperation( op );
        EntryAttribute modAt = new DefaultEntryAttribute( type );
        modAt.add( value );

        mods.add( mod );

        return valid;
    }


    private void delete( Value<?> value )
    {
        if( !cloned.contains( value ) )
        {
            return;
        }
        
        if ( type.isSingleValued() )
        {
            mods.clear();
        }

        Modification mod = new DefaultModification();
        mod.setOperation( ModificationOperation.REMOVE_ATTRIBUTE );
        EntryAttribute modAt = new DefaultEntryAttribute( type );
        modAt.add( value );

        mods.add( mod );
    }


    public boolean add( String value )
    {
        return add( new StringValue( value ) );
    }


    public boolean add( byte[] value )
    {
        return add( new BinaryValue( value ) );
    }


    public boolean add( boolean value )
    {
        return add( String.valueOf( value ) );
    }

}
